package com.soar.tbox;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FilenameFilter;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;

import com.soar.tbox.bean.Command;
import com.soar.tbox.bean.Paramter;
import com.soar.tbox.util.Converts;
import com.soar.tbox.util.SettingHelper;

import android.os.Environment;

/**
 * 加载上行指令文件。
 * @author songjunjie
 *
 */
public class CommandFactory {
	/**
	 * 指令文件存放的文件夹名字
	 */
	private static final String COMMAND_DIR_NAME = "tbox";
	
	/**
	 * 从配置文件中装载上行指令,将装载指令信息保存到CommandStorage中。指令类型+编码作为索引
	 * @throws Exception
	 */
	public static void load() throws Exception {
		String sdPath = Environment.getExternalStorageDirectory().getPath();
		String commandPath = sdPath + File.separator + COMMAND_DIR_NAME;
		File cmdDir = new File(commandPath);
		if (!cmdDir.exists()) {
			throw new FileNotFoundException("在存储卡中没有找到存储指令文件的"
					+ COMMAND_DIR_NAME + "目录！");
		}
		// 找到所有的xml文件
		File[] cmdFiles = cmdDir.listFiles(new FilenameFilter() {
			@Override
			public boolean accept(File dir, String filename) {
				if (filename.endsWith(".xml") && !filename.equals("setting.xml")) {
					return true;
				}
				return false;
			}
		});
		if (cmdFiles.length < 1) {
			throw new FileNotFoundException("在" + COMMAND_DIR_NAME
					+ "目录中没有找到指令文件！");
		}

		for (File cmdFile : cmdFiles) {
			SAXReader reader = new SAXReader();
			Document document;
			try {
				document = reader.read(cmdFile);
			} catch (DocumentException e) {
				e.printStackTrace();
				throw new Exception("读取文件" + cmdFile.getName()
						+ "发生错误!xml文件格式不正确", e);
			}
			
			Command command = new Command();
			
			Element root = document.getRootElement();
			String headStr = root.element("head").getTextTrim();
			headStr = headStr.replaceAll("\\s|b", "");
			Element body = root.element("body");
			String transmitFlagStr = body.selectSingleNode("//transmit_flag").getText().trim();
			String typeStr = body.selectSingleNode("//type").getText().trim();
			String commandNoStr = body.selectSingleNode("//command_no").getText().trim();
			//年份，和时间不使用指定的时间。由程序计算出当前时间
//			String yearStr = body.selectSingleNode("//year").getText().trim();
//			String timeStr = body.selectSingleNode("//time").getText().trim();
			
			String statusFlagStr = null;//状态位
			Node statusFlagNode = body.selectSingleNode("//status_flag");
			if(statusFlagNode != null){
				statusFlagStr = statusFlagNode.getText().trim();
			}
//			
			String markBitStr = null;//标志位
			Node markBitNode = body.selectSingleNode("//mark_bit") ;
			if(markBitNode != null){
				markBitStr = markBitNode.getText().trim();
			}
			
			byte head = Converts.binaryStringToByte(headStr);
			byte[] transmitFlag = Converts.parseHexBinary(transmitFlagStr);
			byte[] type = Converts.parseHexBinary(typeStr);
			byte[] commandNo = Converts.parseHexBinary(commandNoStr);
//			时间采用系统时间
//			byte[] year = Converts.parseHexBinary(yearStr);
//			byte[] time = Converts.parseHexBinary(timeStr);
			int year = Calendar.getInstance().get(Calendar.YEAR);
			year = year%2000;//去后2位。此程序不会用到3000年后。O(∩_∩)O哈哈~
			byte yearHex = Converts.intToUbyte(year);
			int month = Calendar.getInstance().get(Calendar.MONTH)+1;
			SimpleDateFormat sdf = new SimpleDateFormat("MddHHmmss");
			String dateStr = sdf.format(new Date());
			Integer timeInt = Integer.parseInt(dateStr);
			byte[] time = Converts.intToUlong(timeInt);
			byte[] statusFlag = Converts.parseHexBinary(statusFlagStr);
			byte[] markBit = Converts.parseHexBinary(markBitStr);
			command.setHead(head);
			command.setTransmitFlag(transmitFlag[0]);
			command.setType(type[0]);
			command.setCommandNo(commandNo[0]);
			command.setYear(yearHex);
			command.setTime(time);
			if(statusFlag!=null && statusFlag.length>0){
				command.setStatusFlag(statusFlag[0]);
			}
			if(markBit!=null && markBit.length>0){
				command.setMarkBit(markBit[0]);
			}
			
			//参数部分 
			List<Node> paramNodes = body.selectNodes("//param");
			if (paramNodes != null && paramNodes.size() > 0) {
				for (Node paramNode : paramNodes) {
					String keyStr = paramNode.selectSingleNode("./key").getText().trim();
					Node valueLenNode = paramNode.selectSingleNode("./value_len");
					String valueLenStr = valueLenNode.getText().trim();
					Attribute typeAttr1 = ((Element) valueLenNode).attribute("type");
					//参数长度类型，默认为specify，表示人工指定（16进制）；compute表示计算。
					String valueLenType = "specify";
					if(typeAttr1 != null){
						valueLenType = typeAttr1.getText().toLowerCase();
					}
					
					byte[] key = Converts.parseHexBinary(keyStr);
					
					byte[] value = null;
					Node valueNode = paramNode.selectSingleNode("./value");
					Attribute typeAttr = ((Element) valueNode).attribute("type");
					Attribute isvarAttr = ((Element) valueNode).attribute("isvar");
					//参数类型.char，表示参数为字符；hex为16进制字符串；var为变量，需要程序从配置文件中取
					String valueType = "hex";
					if (typeAttr != null) {
						valueType = typeAttr.getText().toLowerCase();
					}
					String isvar = "false";//参数值是否从配置文件中取出。
					if(isvarAttr!=null){
						if(isvarAttr.getText().toLowerCase().equals("true")){
							isvar = "true";
						}
					}
					String valueStr = valueNode.getText();
					
					// 判断所给参数值是用什么形式表示的
					if (valueType.equals("hex")) {// 所给参数值是十六进制形式
						if(isvar.equals("true")){//此值是变量，需要从配置文件中取出值
							valueStr = SettingHelper.getSetting().get(valueStr);
						}
						value = Converts.parseHexBinary(valueStr);
						
					} else if (valueType.equals("char")) {// 所给参数值是字符进制形式
						if(isvar.equals("true")){//此值是变量，需要从配置文件中取出值
							valueStr = SettingHelper.getSetting().get(valueStr);
						}
						if(valueStr!=null){
							value = valueStr.getBytes();
						}else{
							value = new byte[0];
						}
						
					} else {
						throw new Exception("不能识别的参数值类型。文件:"
								+ cmdFile.getName() + " 参数类型：" + valueType);
					}
					//根据配置，在计算参数长度。
					byte[] valueLen = new byte[1];
					if(valueLenType.equals("specify")){
						valueLen = Converts.parseHexBinary(valueLenStr);
					}else{//需要计算长度
						if(markBit!=null && markBit.length> 0 && markBit[0]==0x80){//标识位最高位为1,表示长参数模式
							valueLen = Converts.intToUword(value.length);
						}else{//短参数模式。
							valueLen[0] = Converts.intToUbyte(value.length);
						}
//						valueLen[0] = Converts.intToUbyte(value.length);
					}
					Paramter param = new Paramter();
					param.setKey(key);
					param.setLen(valueLen);
					param.setValue(value);
					command.addParam(param);
//					byte[] param = Converts.asArray(key,valueLen,value);
//					command.addParam(param);
				}
			}
			//将指存储起来。
			String cmdkey = (typeStr+commandNoStr).toLowerCase().replace("h", "");
			CommandStorage.addCommand(cmdkey, command);
		}
	}
}
